package chapter07;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils;
import org.apache.hadoop.io.Text;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

/**
 * @author yuhui
 * descriptions: 完成url解码功能
 * @create 2024 - 12 - 12 3:47 下午
 */
class MyUDFURL extends GenericUDF {
    private transient PrimitiveObjectInspector inputOI;

    // 只调用一次，在任何evaluate()调用之前可以接收到一个可以表示函数输入参数类型的object inspectors数组。
    // initalize用来验证该函数是否接收正确的参数类型和参数个数，最后提供最后结果对应的数据类型。
    public ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException {
        // 检查参数数量
        if (objectInspectors.length != 1) {
            throw new UDFArgumentException("urlDecode() takes only one argument");
        }

        // 检查参数类型
        if (objectInspectors[0].getCategory() != ObjectInspector.Category.PRIMITIVE) {
            throw new UDFArgumentTypeException(0, "Only primitive type arguments are accepted, but "
                    + objectInspectors[0].getTypeName() + " was passed as parameter 1");
        }
        PrimitiveObjectInspector poi = (PrimitiveObjectInspector) objectInspectors[0];
        if (poi.getPrimitiveCategory() != PrimitiveObjectInspector.PrimitiveCategory.STRING) {
            throw new UDFArgumentTypeException(0, "Only String type argument are accepted, but "
                    + poi.getTypeName() + " was passed as parameter 1");
        }

        // 设置输入数据的 ObjectInspector
        inputOI = poi;
        // 输出数据的 ObjectInspector
        return PrimitiveObjectInspectorFactory.writableStringObjectInspector;
    }

    // 真正的逻辑，读取输入数据，处理数据，返回结果。
    public Object evaluate(DeferredObject[] deferredObjects) throws HiveException {
        if (deferredObjects == null || deferredObjects[0] == null) {
            return new Text("");
        }

        // 提取数据
        String component = PrimitiveObjectInspectorUtils.getString(deferredObjects[0].get(), inputOI);
        if (component == null || component.length() <= 0) {
            return new Text("");
        }

        String result = "";
        // 使用%25替换字符串中的%号
        component = component.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
        try {
            result = URLDecoder.decode(component, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            result = component;
        }

        System.out.println(result);
        return new Text(result); // 修改这里，返回 Text 对象
    }

    // 返回描述该方法的字符串
    public String getDisplayString(String[] strings) {
        StringBuilder sb = new StringBuilder();
        sb.append("url_decode");
        sb.append("(");
        if (strings.length > 0) {
            sb.append(strings[0]);
            for (int index = 1; index < strings.length - 1; index++) {
                sb.append(",");
                sb.append(strings[index]);
            }
        }
        sb.append(")");
        return sb.toString();
    }
}